﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using BlueCurve.EnumAction;

namespace ShareCrawler
{
    /// <summary>
    /// Contient les informations pour le traitement du fichier
    /// </summary>
    public class OneFile : EventArgs
    {
        /// <summary>
        /// Taille du fichier
        /// </summary>
        public long Size { get; set; }
        /// <summary>
        /// Date de dernière modification du fichier
        /// </summary>
        public DateTime LastModified { get; set; }
        /// <summary>
        /// Data de création du fichier
        /// </summary>
        public DateTime CreationDate { get; set; }
        /// <summary>
        /// Nom du fichier
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Chemin d'accès du fichier
        /// </summary>
        public string Location { get; set; }
        /// <summary>
        /// Type de traitement à appliquer
        /// </summary>
        public IndexAction Action { get; set; }
    }



    /// <summary>
    /// Class de parcour des disques
    /// </summary>
    public class DriveAccess
    {
        #region 'Configuration'
        /// <summary>
        /// Délégué définissant l'évenement Emit
        /// </summary>
        public delegate void EmitFiles(object sender, OneFile e);
        /// <summary>
        /// Evenemtnt levé dans un fichier est pret à etre traiter
        /// </summary>
        public event EmitFiles LoadFiles;
        /// <summary>
        /// Objet pour la synchronisation
        /// </summary>
        private readonly object m_ThreadsLock = new object();
        /// <summary>
        /// Permet de laisse tourner le thread
        /// </summary>
        private bool m_IsRun = true;


        /// <summary>
        /// Permet d'arreter le thread
        /// </summary>
        public bool IsStop
        {
            set { this.m_IsRun = value; }
        }

        #endregion


        /// <summary>
        /// Parcours les répertoires passer en parametre
        /// </summary>
        /// <param name="inDirectorys">Tableaux des répertoirs à parcourir</param>
        public void GetAllFiles(string[] inDirectorys)
        {
            for (int i = 0; i < inDirectorys.Length; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(GetAllFiles), inDirectorys[i]);
            }
        }

        /// <summary>
        /// Méthode qui récupère tous les fichiers et tous les répertoires. Elle utilise un Stack 
        /// car c'est la meilleur façon de faire avec un algo de scan non recursif
        /// </summary>
        /// <param name="inDirectory">Répertoir à parcourir</param>
        protected void GetAllFiles(object state)
        {
            string inDirectory = state as string;
            Stack<string> myStack = new Stack<string>();
            // Récupération des sous répertoires
            string[] files = Directory.GetFileSystemEntries(inDirectory);
            string poped = null;
            foreach (string fileName in files)
                myStack.Push(fileName);

            while (myStack.Count > 0)
            {
                if (!this.m_IsRun)
                    break;

                poped = myStack.Pop();

                if (Directory.Exists(poped) && (File.GetAttributes(poped) & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    try
                    {
                        files = Directory.GetFileSystemEntries(poped);
                        foreach (string fileName in files)
                        {
                            myStack.Push(fileName);
                        }
                    }
                    catch
                    { }
                }
                else if (File.Exists(poped) && CheckAttributes(poped))
                {
                    if (LoadFiles != null)
                    {
                        FileInfo myFileInfo = new FileInfo(poped);
                        lock (this.m_ThreadsLock)
                        {
                            LoadFiles("", new OneFile()
                            {
                                LastModified = myFileInfo.LastWriteTime,
                                Size = myFileInfo.Length,
                                CreationDate = myFileInfo.CreationTime,
                                Name = myFileInfo.Name,
                                Location = poped
                            });
                        }
                    }
                }
            }
        }



        /// <summary>
        /// Vérifie les attributs de fichiers
        /// afin de s'assurer que l'on a bien le droit de les
        /// traiter
        /// </summary>
        /// <param name="dir">Chemin du fichier</param>
        /// <returns>bool</returns>
        private bool CheckAttributes(string dir)
        {
            if (((File.GetAttributes(dir) & FileAttributes.Encrypted) == FileAttributes.Encrypted)
                || ((File.GetAttributes(dir) & FileAttributes.Hidden) == FileAttributes.Hidden)
                || ((File.GetAttributes(dir) & FileAttributes.Offline) == FileAttributes.Offline)
                || ((File.GetAttributes(dir) & FileAttributes.System) == FileAttributes.System)
                || ((File.GetAttributes(dir) & FileAttributes.Temporary) == FileAttributes.Temporary)
                || ((File.GetAttributes(dir) & FileAttributes.SparseFile) == FileAttributes.SparseFile)
                || ((File.GetAttributes(dir) & FileAttributes.Directory) == FileAttributes.Directory))
            {
                return false;
            }
            return true;
        }
    }
}
